package com.zzzy.doc.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhuozhengsoft.pageoffice.OpenModeType;
import com.zzzy.common.exception.WarningException;
import com.zzzy.common.util.AssertUtil;
import com.zzzy.common.util.CglibBeanCopierUtil;
import com.zzzy.common.util.FileUtil;
import com.zzzy.doc.common.enums.DocStatusEnum;
import com.zzzy.doc.common.enums.UrgencyEnum;
import com.zzzy.doc.dao.entity.DocFile;
import com.zzzy.doc.dao.entity.Document;
import com.zzzy.doc.dao.mapper.DocumentMapper;
import com.zzzy.doc.vo.document.DocBasicInfoRes;
import com.zzzy.doc.vo.document.DocInfoRes;
import com.zzzy.doc.vo.pageoffice.OpenOfficeFileRes;
import com.zzzy.framework.common.dict.DictService;
import com.zzzy.framework.common.enums.sys.DataScopeEnum;
import com.zzzy.framework.common.util.PageOfficeUtil;
import com.zzzy.framework.common.util.SecurityUtils;
import com.zzzy.framework.dto.DataPermissionDto;
import com.zzzy.sys.api.DeptApi;
import com.zzzy.sys.api.UserApi;
import com.zzzy.sys.dto.DeptInfoDto;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 公文基本信息
 *
 * @author fc
 * @since 2024-08-09
 */
@Service
public class DocService extends ServiceImpl<DocumentMapper, Document> {

    @Resource
    protected DocFileService docFileService;
    @Resource
    protected DocUserOperateLinkService docUserOperateLinkService;
    @Resource
    protected UserApi userService;
    @Resource
    protected DeptApi deptService;
    @Resource
    protected DictService dictService;
    @Resource
    protected DocAdviceService docAdviceService;
    @Resource
    protected DocNotifyMessageService docNotifyMessageService;

    public Document getDocById(Long id) {
        Document document = getById(id);
        AssertUtil.nonNull(document, "公文不存在");
        Map<Object, String> urgencyMap = dictService.getDictDataMap(UrgencyEnum.class);
        document.setUrgencyDescription(urgencyMap.get(document.getUrgency()));
        return document;
    }

    public Document getDocByIdForQuery(Long id) {
        Document document = getDocById(id);
        DataPermissionDto dataPermissionDto = SecurityUtils.getLoginUser().getDataPermissionDto();
        Long loginUserId = SecurityUtils.getLoginUser().getId();
        //当前用户为起草人或当前办理人
        if (loginUserId.equals(document.getUserId()) || loginUserId.equals(document.getOperatorId())){
            return document;
        }
        //当前用户为全部数据权限
        if (DataScopeEnum.ALL.getValue().equals(dataPermissionDto.getDataPermission())){
            return document;
        }
        Set<Long> userIdSet = dataPermissionDto.getUserIdSet();
        //当前用户下属用户(包含自己) 为公文起草人/当前办理人/经办人
        if (userIdSet.contains(document.getUserId())
                || userIdSet.contains(document.getOperatorId())
                || docUserOperateLinkService.isContainsLink(id, userIdSet)){
            return document;
        }
        throw new WarningException("当前用户无此公文查看权限");
    }

    public void validateAuthForQuery(Long id) {
        getDocByIdForQuery(id);
    }

    public Document getDocByIdForUpdate(Long id) {
        Document document = getDocByIdForOperate(id);
        Long loginUserId = SecurityUtils.getLoginUser().getId();
        AssertUtil.isEquals(loginUserId, document.getUserId(), "当前用户无此公文修改权限");
        AssertUtil.isEquals(loginUserId, document.getOperatorId(), "当前用户无此公文修改权限");
        return document;
    }

    public Document getDocByIdForOperate(Long id) {
        Document document = getDocById(id);
        Long loginUserId = SecurityUtils.getLoginUser().getId();
        AssertUtil.isEquals(loginUserId, document.getOperatorId(), "当前用户无此公文操作权限");
        return document;
    }

    public DocBasicInfoRes getDocBasicInfo(Long id) {
        validateAuthForQuery(id);
        Document document = getDocById(id);
        DocFile docFile = docFileService.getDocFileByDocId(id);
        DocBasicInfoRes docBasicInfoRes = CglibBeanCopierUtil.copy(docFile, DocBasicInfoRes.class);
        CglibBeanCopierUtil.copy(document, docBasicInfoRes);
        List<Long> mainSendUnitIdList = StringUtils.isBlank(document.getMainSendUnitIds()) ? Collections.emptyList()
                : Arrays.stream(docBasicInfoRes.getMainSendUnitIds().split(",")).map(Long::parseLong).collect(Collectors.toList());
        List<DeptInfoDto> mainSendUnitList = deptService.getDeptDtoList(mainSendUnitIdList);
        List<Long> copySendUnitIdList = StringUtils.isBlank(document.getCopySendUnitIds()) ? Collections.emptyList()
                : Arrays.stream(docBasicInfoRes.getCopySendUnitIds().split(",")).map(Long::parseLong).collect(Collectors.toList());
        List<DeptInfoDto> copySendUnitList = deptService.getDeptDtoList(copySendUnitIdList);
        docBasicInfoRes.setMainSendUnitList(mainSendUnitList);
        docBasicInfoRes.setMainSendUnit(mainSendUnitList.stream().map(DeptInfoDto::getName).collect(Collectors.joining(",")));
        docBasicInfoRes.setCopySendUnitList(copySendUnitList);
        docBasicInfoRes.setCopySendUnit(copySendUnitList.stream().map(DeptInfoDto::getName).collect(Collectors.joining(",")));
        return docBasicInfoRes;
    }


    public DocInfoRes getDocInfo(Long id) {
        validateAuthForQuery(id);
        Document document = getDocById(id);
        DocFile docFile = docFileService.getDocFileByDocId(id);
        DocInfoRes docInfoRes = CglibBeanCopierUtil.copy(docFile, DocInfoRes.class);
        CglibBeanCopierUtil.copy(document, docInfoRes);
        return docInfoRes;
    }
    /**
     * 无论是拟稿人 还是 审核人 打开均只读
     */
    public OpenOfficeFileRes getApprovalPageOfficeResByDocId(Long id, String openFileUrl) {
        validateAuthForQuery(id);
        DocInfoRes docInfo = getDocInfo(id);
        boolean isCurrentOperator = docInfo.getOperatorId().equals(SecurityUtils.getLoginUser().getId());
        boolean isDistribute = DocStatusEnum.DISTRIBUTE.getValue().equals(docInfo.getStatus());
        boolean isComplete = DocStatusEnum.COMPLETE.getValue().equals(docInfo.getStatus());
        boolean isCancel = DocStatusEnum.CANCEL.getValue().equals(docInfo.getStatus());
        boolean isArchived = DocStatusEnum.ARCHIVED.getValue().equals(docInfo.getStatus());
        //如果不是当前操作人则只读
        if (!isCurrentOperator || isComplete || isCancel || isDistribute || isArchived){
            return getReadOnlyPageOfficeRes(openFileUrl, id);
        }
        //是否拟稿人
        boolean isDrafter = docInfo.getUserId().equals(SecurityUtils.getLoginUser().getId());
        String fileName = docInfo.getSubject() + "." + FileUtil.getFileType(docInfo.getApprovalFileBlob());

        String wordHtml = PageOfficeUtil.getWordHtml(openFileUrl, fileName, OpenModeType.docReadOnly);
        if (isDrafter){
            return OpenOfficeFileRes.builder().html(wordHtml).build();
        } else {
            return OpenOfficeFileRes.builder().html(wordHtml).edit(true).build();
        }
    }

    public OpenOfficeFileRes getMainPageOfficeResByDocId(Long id, String openFileUrl) {
        validateAuthForQuery(id);
        DocInfoRes docInfo = getDocInfo(id);
        //是否当前可操作人
        boolean isCurrentOperator = docInfo.getOperatorId().equals(SecurityUtils.getLoginUser().getId());
        boolean isDistribute = DocStatusEnum.DISTRIBUTE.getValue().equals(docInfo.getStatus());
        boolean isComplete = DocStatusEnum.COMPLETE.getValue().equals(docInfo.getStatus());
        boolean isCancel = DocStatusEnum.CANCEL.getValue().equals(docInfo.getStatus());
        boolean isArchived = DocStatusEnum.ARCHIVED.getValue().equals(docInfo.getStatus());
        //如果不是当前操作人则只读
        if (!isCurrentOperator || isComplete || isCancel || isDistribute || isArchived){
            return getReadOnlyPageOfficeRes(openFileUrl, id);
        }
        String wordFileName = docInfo.getSubject()
                + "." + FileUtil.getFileType(docInfo.getApprovalFileBlob());
        OpenModeType openModeType;
        //是否拟稿人
        boolean isDrafter = docInfo.getUserId().equals(SecurityUtils.getLoginUser().getId());
        if (isDrafter){
            if (DocStatusEnum.RED_SHEET_TEMPLATE.getValue().equals(docInfo.getStatus())){
                openModeType = OpenModeType.docAdmin;
            } else {
                openModeType = OpenModeType.docRevisionOnly;
            }
        } else {
            openModeType = OpenModeType.docCommentOnly;
        }
        String wordHtml = PageOfficeUtil.getWordHtml(openFileUrl, wordFileName, openModeType);
        return OpenOfficeFileRes.builder().html(wordHtml).edit(true).build();
    }

    public OpenOfficeFileRes getFinalPageOfficeResByDocId(Long id, String openFileUrl) {
        validateAuthForQuery(id);
        DocInfoRes docInfo = getDocInfo(id);
        //是否当前可操作人
        boolean isCurrentOperator = docInfo.getOperatorId().equals(SecurityUtils.getLoginUser().getId());
        if (!isCurrentOperator){
            return getReadOnlyPageOfficeRes(openFileUrl, id);
        }
        String pdfFileName = docInfo.getSubject() + "." + FileUtil.PDF;
        String pdfHtml = PageOfficeUtil.getPdfHtml(openFileUrl, pdfFileName);
        boolean isSign = DocStatusEnum.SIGN.getValue().equals(docInfo.getStatus());
        return OpenOfficeFileRes.builder().html(pdfHtml).pdf(true).edit(isSign).build();
    }
    private OpenOfficeFileRes getReadOnlyPageOfficeRes(String openFileUrl, Long docId) {
        DocInfoRes docInfo = getDocInfo(docId);
        if (Objects.nonNull(docInfo.getPdfFileBlob())){
            String fileName = docInfo.getSubject() + "." + FileUtil.PDF;
            String pdfReadOnlyHtml = PageOfficeUtil.getPdfHtml(openFileUrl, fileName);
            return OpenOfficeFileRes.builder().html(pdfReadOnlyHtml).pdf(true).build();
        } else {
            String fileName = docInfo.getSubject() + "." + FileUtil.getFileType(docInfo.getApprovalFileBlob());
            String wordHtml = PageOfficeUtil.getWordHtml(openFileUrl, fileName, OpenModeType.docReadOnly);
            return OpenOfficeFileRes.builder().html(wordHtml).build();
        }
    }
    public void updateApprovalWord(Long id, byte[] byteArray) {
        docFileService.updateApprovalByDocId(id, byteArray);
        Document document = getDocById(id);
        document.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(document);
    }
    public void updateMainWord(Long id, byte[] byteArray, Integer revisionCount) {
        docFileService.updateMainByDocId(id, byteArray, revisionCount);

        Document document = getDocById(id);
        document.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(document);
    }
    public void updateFinalPdf(Long id, byte[] byteArray) {
        docFileService.updateFinalPdfByDocId(id, byteArray);

        Document document = getDocById(id);
        document.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(document);
    }
}
